#pragma once

#include <Ray.hpp>
#include <memory>
#include <vector>

class Material;

struct HitRecord {
  glm::vec3 p;
  glm::vec3 normal;
  float t;
  bool front;
  Material* material;

  inline void SetFaceNormal(const Ray& ray, const glm::vec3& outward_normal) {
    front = glm::dot(ray.Direction(), outward_normal) < 0.f;
    normal = front ? outward_normal : -outward_normal;
  }
};

class Hittable {
 public:
  virtual ~Hittable() = default;

  virtual bool Hit(const Ray& ray, float t_min, float t_max,
                   HitRecord& rec) const = 0;
};

class HittableList : public Hittable {
 public:
  HittableList() = default;
  ~HittableList() override = default;

  void ClearObjects();

  void AddObject(std::shared_ptr<Hittable> object);

  bool Hit(const Ray& ray, float t_min, float t_max,
           HitRecord& rec) const override;

 private:
  std::vector<std::shared_ptr<Hittable>> mObjects;
};
